package com.judge.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.api.domain.UserExeResult;
import com.api.domain.dto.JudgeSubmitDTO;
import com.api.domain.vo.UserQuestionResultVO;
import com.common.core.constants.Constants;
import com.common.core.constants.JudgeConstants;
import com.common.core.enums.CodeRunStatus;
import com.judge.domain.SandBoxExecuteResult;
import com.judge.domain.UserSubmit;
import com.judge.mapper.UserSubmitMapper;
import com.judge.service.IJudgeService;
import com.judge.service.ISandboxPoolService;
import com.judge.service.ISandboxService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class JudgeServiceImpl implements IJudgeService {

    @Autowired
    private ISandboxService sandboxService;

    @Autowired
    private ISandboxPoolService sandboxPoolService;

    @Autowired
    private UserSubmitMapper userSubmitMapper;

    @Override
    public UserQuestionResultVO doJudgeJavaCode(JudgeSubmitDTO judgeSubmitDTO) {
        SandBoxExecuteResult sandBoxExecuteResult =
                sandboxService.exeJavaCode(judgeSubmitDTO.getUserId(), judgeSubmitDTO.getUserCode(), judgeSubmitDTO.getInputList());
        UserQuestionResultVO userQuestionResultVO = new UserQuestionResultVO();
        if (sandBoxExecuteResult != null && CodeRunStatus.SUCCEED.equals(sandBoxExecuteResult.getRunStatus())) {
            //比对直接结果  时间限制  空间限制的比对
            userQuestionResultVO = doJudge(judgeSubmitDTO, sandBoxExecuteResult, userQuestionResultVO);
        } else {
            // 编译失败或运行时错误时，也要创建测试用例结果供前端显示
            List<UserExeResult> userExeResultList = new ArrayList<>();
            List<String> inputList = judgeSubmitDTO.getInputList();
            List<String> outputList = judgeSubmitDTO.getOutputList();
            
            // 为每个测试用例创建结果，显示编译/运行错误
            for (int i = 0; i < Math.max(inputList.size(), outputList.size()); i++) {
                UserExeResult userExeResult = new UserExeResult();
                userExeResult.setInput(i < inputList.size() ? inputList.get(i) : "");
                userExeResult.setOutput(i < outputList.size() ? outputList.get(i) : "");
                userExeResult.setExeOutput("编译或运行失败");
                userExeResultList.add(userExeResult);
            }
            
            userQuestionResultVO.setUserExeResultList(userExeResultList);
            userQuestionResultVO.setPass(Constants.FALSE);
            if (sandBoxExecuteResult != null) {
                userQuestionResultVO.setExeMessage(sandBoxExecuteResult.getExeMessage());
            } else {
                userQuestionResultVO.setExeMessage(CodeRunStatus.UNKNOWN_FAILED.getMsg());
            }
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
        }
        saveUserSubmit(judgeSubmitDTO, userQuestionResultVO);
        log.info("判题逻辑结束，判题结果为： {} ", userQuestionResultVO);
        log.info("测试用例结果数量: {}", userQuestionResultVO.getUserExeResultList() != null ? userQuestionResultVO.getUserExeResultList().size() : 0);
        if (userQuestionResultVO.getUserExeResultList() != null && !userQuestionResultVO.getUserExeResultList().isEmpty()) {
            log.info("第一个测试用例: 输入={}, 期望输出={}, 实际输出={}", 
                    userQuestionResultVO.getUserExeResultList().get(0).getInput(),
                    userQuestionResultVO.getUserExeResultList().get(0).getOutput(),
                    userQuestionResultVO.getUserExeResultList().get(0).getExeOutput());
        }
        return userQuestionResultVO;
    }

    private UserQuestionResultVO doJudge(JudgeSubmitDTO judgeSubmitDTO,
                                         SandBoxExecuteResult sandBoxExecuteResult,
                                         UserQuestionResultVO userQuestionResultVO) {
        List<String> exeOutputList = sandBoxExecuteResult.getOutputList();
        List<String> outputList = judgeSubmitDTO.getOutputList();
        List<UserExeResult> userExeResultList = new ArrayList<>();
        
        if (outputList.size() != exeOutputList.size()) {
            // 输出数量不匹配时，也要创建测试用例结果供前端显示
            log.warn("输出数量不匹配: 期望{}个，实际{}个", outputList.size(), exeOutputList.size());
            
            // 创建测试用例结果，显示不匹配的情况
            int maxSize = Math.max(outputList.size(), exeOutputList.size());
            for (int i = 0; i < maxSize; i++) {
                UserExeResult userExeResult = new UserExeResult();
                userExeResult.setInput(i < judgeSubmitDTO.getInputList().size() ? judgeSubmitDTO.getInputList().get(i) : "");
                userExeResult.setOutput(i < outputList.size() ? outputList.get(i) : "无期望输出");
                userExeResult.setExeOutput(i < exeOutputList.size() ? exeOutputList.get(i) : "无实际输出");
                userExeResultList.add(userExeResult);
            }
            
            userQuestionResultVO.setUserExeResultList(userExeResultList);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
            return userQuestionResultVO;
        }
        
        boolean passed = resultCompare(judgeSubmitDTO, exeOutputList, outputList, userExeResultList);
        return assembleUserQuestionResultVO(judgeSubmitDTO, sandBoxExecuteResult, userQuestionResultVO, userExeResultList, passed);
    }

    private UserQuestionResultVO assembleUserQuestionResultVO(JudgeSubmitDTO judgeSubmitDTO,
                                                              SandBoxExecuteResult sandBoxExecuteResult,
                                                              UserQuestionResultVO userQuestionResultVO,
                                                              List<UserExeResult> userExeResultList, boolean passed) {
        userQuestionResultVO.setUserExeResultList(userExeResultList);
        if (!passed) {
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.NOT_ALL_PASSED.getMsg());
            return userQuestionResultVO;
        }
        // 内存限制检查：judgeSubmitDTO.getSpaceLimit()是KB，sandBoxExecuteResult.getUseMemory()是字节
        // 需要将KB转换为字节进行比较
        Long spaceLimitInBytes = judgeSubmitDTO.getSpaceLimit() * 1024; // KB转字节
        if (sandBoxExecuteResult.getUseMemory() > spaceLimitInBytes) {
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_MEMORY.getMsg());
            log.warn("代码执行超出内存限制: 使用内存={}bytes({}KB), 限制内存={}KB({}bytes)", 
                    sandBoxExecuteResult.getUseMemory(), sandBoxExecuteResult.getUseMemory()/1024,
                    judgeSubmitDTO.getSpaceLimit(), spaceLimitInBytes);
            return userQuestionResultVO;
        }
        // 时间限制检查：judgeSubmitDTO.getTimeLimit()是毫秒，sandBoxExecuteResult.getUseTime()也是毫秒
        if (sandBoxExecuteResult.getUseTime() > judgeSubmitDTO.getTimeLimit()) {
            userQuestionResultVO.setPass(Constants.FALSE);
            userQuestionResultVO.setScore(JudgeConstants.ERROR_SCORE);
            userQuestionResultVO.setExeMessage(CodeRunStatus.OUT_OF_TIME.getMsg());
            log.warn("代码执行超时: 使用时间={}ms, 限制时间={}ms", 
                    sandBoxExecuteResult.getUseTime(), judgeSubmitDTO.getTimeLimit());
            return userQuestionResultVO;
        }
        userQuestionResultVO.setPass(Constants.TRUE);
        int score = judgeSubmitDTO.getDifficulty() * JudgeConstants.DEFAULT_SCORE;
        userQuestionResultVO.setScore(score);
        return userQuestionResultVO;
    }

    private boolean resultCompare(JudgeSubmitDTO judgeSubmitDTO, List<String> exeOutputList,
                                  List<String> outputList, List<UserExeResult> userExeResultList) {
        boolean passed = true;
        log.info("开始比较结果，测试用例数量: {}", outputList.size());
        
        for (int index = 0; index < outputList.size(); index++) {
            String output = outputList.get(index);
            String exeOutPut = exeOutputList.get(index);
            String input = judgeSubmitDTO.getInputList().get(index);
            
            log.info("测试用例 {}: 输入=[{}], 期望输出=[{}], 实际输出=[{}]", 
                    index + 1, input, output, exeOutPut);
            log.info("期望输出长度: {}, 实际输出长度: {}", output.length(), exeOutPut.length());
            
            UserExeResult userExeResult = new UserExeResult();
            userExeResult.setInput(input);
            userExeResult.setOutput(output);
            userExeResult.setExeOutput(exeOutPut);
            userExeResultList.add(userExeResult);
            
            // 使用改进后的输出比较策略
            boolean isMatch = compareOutput(output, exeOutPut);
            
            if (!isMatch) {
                passed = false;
                log.warn("测试用例 {} 失败: 输入=[{}]", index + 1, input);
                log.warn("期望输出: [{}]", output);
                log.warn("实际输出: [{}]", exeOutPut);
                log.warn("期望输出字符详情: {}", getCharDetails(output));
                log.warn("实际输出字符详情: {}", getCharDetails(exeOutPut));
            } else {
                log.info("测试用例 {} 通过", index + 1);
            }
        }
        
        log.info("结果比较完成，通过状态: {}", passed);
        return passed;
    }
    
    private String getCharDetails(String str) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (c == '\n') {
                sb.append("\\n");
            } else if (c == '\r') {
                sb.append("\\r");
            } else if (c == '\t') {
                sb.append("\\t");
            } else if (c == ' ') {
                sb.append("(space)");
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }
    
    /**
     * 改进的输出结果比较策略
     * 1. 标准化行尾换行符（\r\n -> \n）
     * 2. 去除首尾空白
     * 3. 支持不同的比较模式
     */
    private boolean compareOutput(String expected, String actual) {
        if (expected == null && actual == null) {
            return true;
        }
        if (expected == null || actual == null) {
            return false;
        }
        
        // 标准化行尾换行符
        String normalizedExpected = normalizeLineEndings(expected);
        String normalizedActual = normalizeLineEndings(actual);
        
        // 去除首尾空白
        String trimmedExpected = normalizedExpected.trim();
        String trimmedActual = normalizedActual.trim();
        
        // 精确匹配
        if (trimmedExpected.equals(trimmedActual)) {
            return true;
        }
        
        // 如果精确匹配失败，尝试忽略所有空白符
        String expectedNoWhitespace = trimmedExpected.replaceAll("\\s+", "");
        String actualNoWhitespace = trimmedActual.replaceAll("\\s+", "");
        
        return expectedNoWhitespace.equals(actualNoWhitespace);
    }
    
    /**
     * 标准化行尾换行符
     */
    private String normalizeLineEndings(String text) {
        if (text == null) {
            return null;
        }
        // 将 \r\n 和 \r 都转换为 \n
        return text.replace("\r\n", "\n").replace("\r", "\n");
    }

    private void saveUserSubmit(JudgeSubmitDTO judgeSubmitDTO, UserQuestionResultVO userQuestionResultVO) {
        UserSubmit userSubmit = new UserSubmit();
        userSubmit.setUserId(judgeSubmitDTO.getUserId());
        userSubmit.setQuestionId(judgeSubmitDTO.getQuestionId());
        userSubmit.setExamId(judgeSubmitDTO.getExamId());
        userSubmit.setProgramType(judgeSubmitDTO.getProgramType());
        userSubmit.setUserCode(judgeSubmitDTO.getUserCode());
        userSubmit.setPass(userQuestionResultVO.getPass());
        userSubmit.setScore(userQuestionResultVO.getScore());
        userSubmit.setCreateBy(judgeSubmitDTO.getUserId());
        
        // 截断过长的exeMessage，避免数据库字段长度超限（varchar(255)）
        String exeMessage = userQuestionResultVO.getExeMessage();
        if (exeMessage != null) {
            if (exeMessage.length() > 250) {
                exeMessage = exeMessage.substring(0, 250) + "...(已截断)";
                log.warn("exeMessage过长已截断，原始长度: {}, 截断后长度: {}", 
                        userQuestionResultVO.getExeMessage().length(), exeMessage.length());
            }
        }
        userSubmit.setExeMessage(exeMessage);
        
        // 处理caseJudgeRes
        String caseJudgeResJson = JSON.toJSONString(userQuestionResultVO.getUserExeResultList());
        userSubmit.setCaseJudgeRes(caseJudgeResJson);
        
        // 截断过长的caseJudgeRes，避免数据库字段长度超限
        if (caseJudgeResJson != null && caseJudgeResJson.length() > 5000) {
            caseJudgeResJson = caseJudgeResJson.substring(0, 5000) + "...(JSON过长已截断)";
            userSubmit.setCaseJudgeRes(caseJudgeResJson);
            log.warn("caseJudgeRes过长已截断，原始长度: {}, 截断后长度: {}", 
                    JSON.toJSONString(userQuestionResultVO.getUserExeResultList()).length(), caseJudgeResJson.length());
        }
        
        // 设置时间字段
        LocalDateTime now = LocalDateTime.now();
        userSubmit.setCreateTime(now);
        userSubmit.setUpdateTime(now);
        userSubmit.setUpdateBy(judgeSubmitDTO.getUserId());
        
        userSubmitMapper.delete(new LambdaQueryWrapper<UserSubmit>()
                .eq(UserSubmit::getUserId, judgeSubmitDTO.getUserId())
                .eq(UserSubmit::getQuestionId, judgeSubmitDTO.getQuestionId())
                .isNull(judgeSubmitDTO.getExamId() == null, UserSubmit::getExamId)
                .eq(judgeSubmitDTO.getExamId() != null, UserSubmit::getExamId, judgeSubmitDTO.getExamId()));
        userSubmitMapper.insert(userSubmit);
    }
}
